#include "stdafx.h"
#include "tdd.h"
#include "tddassert.h"

#include "..\\SmartPtr\\ObjectWrapper.h"
#include "..\\SmartPtr\\WrapperManager.h"

class MockObject : public CObjectWrapper
{
public:
	MockObject(void * p): CObjectWrapper() 
	{
		m_pRawPointer = p;
	}

	virtual int AddRef() {return m_count++;}
	virtual int Release() {return m_count--;}
};

namespace SmartPtr
{
	namespace UnitTest
	{
		TESTCLASS(CWrapperManagerTests)
		{
			virtual void ClassInitialize()
			{
			}

			virtual void ClassCleanup()
			{
			}

			virtual void TestCleanup()
			{
				CWrapperManager::Destroy();	
			}

			TESTMETHOD(TestGetRefCount)
			{
				int * p1 = new int;
				
				MockObject * mockObj = new MockObject(p1);
				CWrapperManager::GetInstance()->Insert(mockObj);
				TDD_VERIFY(CWrapperManager::GetInstance()->GetRefCount(p1) == 1);

				mockObj->AddRef();
				TDD_VERIFY(CWrapperManager::GetInstance()->GetRefCount(p1) == 2);
				
				// we do not need to delete mockObj, which will be deleted
				// in the CWrapperManager::Destroy();
				// but as we do not use the DESTROYFUN, so we will have to delete the int
				delete p1;
			}
			
			TESTMETHOD(TestAddObject)
			{
				CWrapperManager::GetInstance()->Insert(NULL);
				TDD_VERIFY(CWrapperManager::GetInstance()->GetObjectCount() == 0);

				int * p1 = new int;
				MockObject *mockObj = new MockObject(p1);
				CWrapperManager::GetInstance()->Insert(mockObj);
				TDD_VERIFY(CWrapperManager::GetInstance()->GetObjectCount() == 1);

				int * p2 = new int;
				MockObject *mockObj2 = new MockObject(p2);
				CWrapperManager::GetInstance()->Insert(mockObj2);
				TDD_VERIFY(CWrapperManager::GetInstance()->GetObjectCount() == 2);

				delete p1;
				delete p2;
			}

			TESTMETHOD(TestRemoveObject)
			{
				int * p1 = new int;
				MockObject *mockObj = new MockObject(p1);
				CWrapperManager::GetInstance()->Insert(mockObj);
				TDD_VERIFY(CWrapperManager::GetInstance()->GetObjectCount() == 1);

				int * p2 = new int;
				MockObject *mockObj2 = new MockObject(p2);
				CWrapperManager::GetInstance()->Insert(mockObj2);
				TDD_VERIFY(CWrapperManager::GetInstance()->GetObjectCount() == 2);

				CWrapperManager::GetInstance()->Remove(NULL);
				TDD_VERIFY(CWrapperManager::GetInstance()->GetObjectCount() == 2);

				CWrapperManager::GetInstance()->Remove(mockObj2);
				TDD_VERIFY(CWrapperManager::GetInstance()->GetObjectCount() == 1);
			
				CWrapperManager::GetInstance()->Remove(mockObj);
				TDD_VERIFY(CWrapperManager::GetInstance()->GetObjectCount() == 0);
			}

			TESTMETHOD(TestNullObject)
			{
				CObjectWrapper *obj = CWrapperManager::GetInstance()->WrapObject<int>(NULL);
				TDD_VERIFY(obj->GetRawPointer() == NULL);
			}

			TESTMETHOD(TestWrapObject)
			{
				int *p = new int;
				CObjectWrapper *obj = CWrapperManager::GetInstance()->WrapObject<int>(p);
				TDD_VERIFY(obj->GetRefCount() == 1);
				TDD_VERIFY(obj->GetRawPointer() == (void*)p);

				obj->AddRef();
				TDD_VERIFY(obj->GetRefCount() == 2);
				TDD_VERIFY(obj->GetRawPointer() == (void*)p);

				// we do not need to delete the p1 and p2, for WrapObject use the CSingleObjectWrapper,
				// which will delete them in the deconstructor.
			}

			TESTMETHOD(TestWrapSameObject)
			{
				int *p = new int;
				CObjectWrapper *obj = CWrapperManager::GetInstance()->WrapObject<int>(p);
				CWrapperManager::GetInstance()->WrapObject<int>(p);
				TDD_VERIFY(obj->GetRefCount() == 2);
				TDD_VERIFY(obj->GetRawPointer() == (void*)p);

				// we do not need to delete the p, for WrapObject use the CSingleObjectWrapper,
				// which will delete them in the deconstructor.
			}

			TESTMETHOD(TestIsEmbeddedPtr_Valid)
			{
				// the 'p' will not put into the m_wrapper
				int *p = NULL;
				CObjectWrapper *obj = CWrapperManager::GetInstance()->WrapObject<int>(p);
				
				TDD_VERIFY( CWrapperManager::GetInstance()->IsEmbeddedPtr(p) == false);
			}
		};
	}
}